﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://wpfimageviewer.codeplex.com
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Windows;
using System.Windows.Threading;
using BrainTechLLC;
using ImageAppDataModels;
using ImageAppViewModels;
using BrainTechLLC.WPF;
using WpfImageDuplicates;
using System.Collections.ObjectModel;

namespace FullViewer.Plugin
{
    public class FullViewerWindowHandler : WindowHandlerBase<FullViewerWindow, FileImageViewModel>, IFullViewerWindowHandler
    {
        public event EventHandler Closed;
        public static PluginDefinitionLoaded<IFullViewerWindowHandler> Handler;
        public event EventHandler<ObjectEventArgsNonRef<FileImageViewModel, bool>> RequestDelete;
        public event EventHandler<ObjectEventArgsNonRef<FileImageViewModel, bool>> RequestResizeDelete;
        public event EventHandler<ObjectEventArgsNonRef<FileImageViewModel, bool>> RequestResize;
        public event EventHandler<ObjectEventArgsNonRef<RotationParams, bool>> RequestRotate;

        protected FileImageViewModel _vmFull;
        protected PreLoader<Bitmap> _preloader = new PreLoader<Bitmap>(1, System.Threading.ThreadPriority.BelowNormal, false);
        public SimpleDispatcherTimer _dt;

        public PreLoader<Bitmap> BitmapPreloader
        {
            get { return _preloader; }
        }

        public FileImageViewModel ImageViewModel
        {
            get { return _vmFull; }
        }

        public FullViewerWindowHandler(Window1 parentWindow, PluginDefinitionLoaded<IFullViewerWindowHandler> handler)
            : base(parentWindow)
        {
            Handler = handler;
            _parentWindow = parentWindow;
            _preloader.PreloadComplete += new EventHandler<ObjectEventArgs<ICanBePreloaded<Bitmap>>>(_preloader_PreloadComplete);
            _dt = new SimpleDispatcherTimer(DispatcherPriority.Input, 70, timer => TimerTick(timer));
            _dt.Start();
        }

        void _preloader_PreloadComplete(object sender, ObjectEventArgs<ICanBePreloaded<Bitmap>> e)
        {
            if (_window != null && _vmFull != null)
            {
                try
                {
                    FileImage fi = e.obj as FileImage;

                    if (_window != null && _vmFull != null)
                    {
                        var nextPrev = GetNextAndPreviousFileImages();

                        for (int n = 0; n < nextPrev.Count; n++)
                        {
                            var preload = nextPrev[n];

                            if (preload == fi)
                            {
                                if (preload.ImageSourceCached == null && !(preload as FileImage)._lazyLoadingImageSource)
                                {
                                    var cvm = FindFileImageCollection(preload.FileName);
                                    var found = cvm.Find(preload.FileName);

                                    if (found != null)
                                    {
                                        found.SetCurrentWidthHeight(_window.fullView.ActualWidth, _window.fullView.ActualHeight);
                                        found.GetImageSource();
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }
        }

        public override void OpenWindow(FileImageViewModel vm)
        {
            Debug.WriteLine(vm.FileImage.BitmapCached == null ? vm.FileName + " was not cached" : vm.FileName + " was cached");

            if (_windowClosed)
            {
                _window = null;
            }

            _windowClosed = false;

            if (_vmFull != null)
            {
                _vmFull.PropertyChanged -= vm_PropertyChanged;
                _vmFull.Item.Filters.CollectionChanged -= FilterCollection_CollectionChanged;
            }

            _vmFull = vm;
            _vmFull.PropertyChanged += new PropertyChangedEventHandler(vm_PropertyChanged);
            _vmFull.Item.Filters.CollectionChanged += new NotifyCollectionChangedEventHandler(FilterCollection_CollectionChanged);

            if (_window == null)
            {
                _window = CreateNewFullViewerWindow();
                _window.FileImageViewModel = _vmFull;
            }
            else
            {
                _window.FileImageViewModel = _vmFull;
                _window.FitSaved();
                _window.Show();
            }

            if (Settings.Values.TrackLocationInThumbView)
            {
                Window1.MainWindow.Dispatcher.BeginInvoke(new VoidDelegate(() =>
                {
                    Window1.MainWindow.CollectionViews.ForEach(o => o.ClearSelected());
                    Window1.MainWindow.CollectionViews.ForEach(o => o.ToggleSelection(_vmFull, true));
                }), DispatcherPriority.Send);
            }

            _window.Topmost = Settings.Values.ViewerIsTopmost;

            _dt.Tag = _vmFull;
            _dt.Start();

            _window.Focus();

            Window1.MainWindow.Dispatcher.BeginInvoke(new VoidDelegate(() =>
            {
                _window.Focus();
                _window.Activate();
                _window.fullView.scroller.ScrollToHome();
            }), DispatcherPriority.Normal);
        }

        protected RunInitializationResult TimerTick(SimpleDispatcherTimer timer)
        {
            FileImageViewModel vm = timer.Tag as FileImageViewModel;
            timer.Tag = null;

            if (_window != null)
            {
                _preloader.Clear();

                if (_vmFull != null)
                {
                    if (_vmFull == vm)
                    {
                        _preloader.AddPreloads(GetNextAndPreviousFileImages().Cast<ICanBePreloaded<Bitmap>>().ToList());
                        return RunInitializationResult.StopTimer;
                    }
                    else
                    {
                        timer.Tag = _vmFull;
                        return RunInitializationResult.DidSomething;
                    }
                }
            }

            return RunInitializationResult.DidntDoAnything;
        }

        private FullViewerWindow CreateNewFullViewerWindow()
        {
            FullViewerWindow viewer = new FullViewerWindow()
            {
                WindowStartupLocation = WindowStartupLocation.Manual,
            };
            viewer.WantNextImage += new EventHandler(newWindow_WantNextImage);
            viewer.WantPreviousImage += new EventHandler(newWindow_WantPreviousImage);
            viewer.RequestDelete += new EventHandler<ObjectEventArgsNonRef<FileImageViewModel, bool>>(viewer_RequestDelete);
            viewer.Closed += new EventHandler(_newWindow_Closed);
            viewer.RequestResize += new EventHandler<ObjectEventArgsNonRef<FileImageViewModel, bool>>(viewer_RequestResize);
            viewer.RequestResizeDelete += new EventHandler<ObjectEventArgsNonRef<FileImageViewModel, bool>>(viewer_RequestResizeDelete);
            viewer.RequestRotate += new EventHandler<ObjectEventArgsNonRef<RotationParams, bool>>(viewer_RequestRotate);
            viewer.Closing += new CancelEventHandler(viewer_Closing);

            viewer.Left = Settings.Values.FullLeft;
            viewer.Top = Settings.Values.FullTop;
            viewer.Width = Settings.Values.FullWidth;
            viewer.Height = Settings.Values.FullHeight;
            viewer.FitSaved();

            viewer.HorizontalAlignment = HorizontalAlignment.Stretch;
            viewer.VerticalAlignment = VerticalAlignment.Stretch;
            viewer.Show();
            viewer.FitSaved();
            viewer.HookupEvents();

            if (viewer.IsVisible && Settings.Values.FullViewerLocation != null)
            {
                viewer.Left = Settings.Values.FullViewerLocation.Left;
                viewer.Top = Settings.Values.FullViewerLocation.Top;
                viewer.Width = Settings.Values.FullViewerLocation.Width;
                viewer.Height = Settings.Values.FullViewerLocation.Height;
            }


            return viewer;
        }

        void viewer_Closing(object sender, CancelEventArgs e)
        {
            FileImageCollectionViewModel cvm = null;
            if (_window.FileImageViewModel != null)
            {
                cvm = FindFileImageCollection(_window.FileImageViewModel.FileName);
                if (cvm != null)
                {
                    cvm._currentIndex = -1;
                }
            }
        }

        void viewer_RequestRotate(object sender, ObjectEventArgsNonRef<RotationParams, bool> e)
        {
            RequestRotate.RaiseEvent(this, e.obj1, e.obj2);
        }

        void viewer_RequestResizeDelete(object sender, ObjectEventArgsNonRef<FileImageViewModel, bool> e)
        {
            RequestResizeDelete.RaiseEvent(this, e.obj1, e.obj2);
        }

        void viewer_RequestResize(object sender, ObjectEventArgsNonRef<FileImageViewModel, bool> e)
        {
            RequestResize.RaiseEvent(this, e.obj1, e.obj2);
        }

        void viewer_RequestDelete(object sender, ObjectEventArgsNonRef<FileImageViewModel, bool> e)
        {
            RequestDelete.RaiseEvent(this, e.obj1, e.obj2);
        }

        public void FilterChanged()
        {
            if (_window != null)
            {
                _window.FileImageViewModel.NotifyImageChanged();
            }
        }

        private void FilterCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (_window != null)
            {
                _window.FileImageViewModel.NotifyImageChanged();
            }
        }

        public ObservableCollection<ImageCollectionView> CollectionViews
        {
            get { return Window1.MainWindow.CollectionViews; }
        }

        public ObservableCollection<FileImageCollectionViewModel> CollectionViewModels
        {
            get { return Window1.MainWindow._AllFileImageCollectionViewModels; }
        }

        public ImageCollectionView FindCollectionView(string fileName)
        {
            return CollectionViews.FirstOrDefault(o => o._vm.Find(fileName) != null);
        }

        public FileImageCollectionViewModel FindFileImageCollection(string fileName)
        {
            return CollectionViewModels.FirstOrDefault(o => o.Find(fileName) != null);
        }

        public List<IFileImage> GetNextAndPreviousFileImages()
        {
            List<IFileImage> results = new List<IFileImage>();

            if (_window != null)
            {
                var image = FindFileImageCollection(_vmFull.FileName).GetPrevious(_vmFull.FileName, false);

                if (image != null)
                    results.Add(image.FileImage);

                image = FindFileImageCollection(_vmFull.FileName).GetNext(_vmFull.FileName, false);

                if (image != null)
                    results.Add(image.FileImage);
            }

            return results;
        }

        public List<FileImageViewModel> GetNextAndPrevious()
        {
            List<FileImageViewModel> results = new List<FileImageViewModel>();

            if (_window != null)
            {
                var image = FindFileImageCollection(_window.FileImageViewModel.FileName).GetPrevious(_window.FileImageViewModel.FileName, false);

                if (image != null)
                    results.Add(image);

                image = FindFileImageCollection(_window.FileImageViewModel.FileName).GetNext(_window.FileImageViewModel.FileName, false);

                if (image != null)
                    results.Add(image);
            }

            return results;
        }

        private void vm_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (_window != null)
            {
                FileImageViewModel vm = sender as FileImageViewModel;

                if (e.PropertyName == "ImageSource" || e.PropertyName == "TransformedBitmap")
                {
                    if (vm.Item.ImageSourceCached != null && (vm.FileImage as FileImage).TransformedBitmapCached != null)
                    {
                        if (Settings.Values.TrackLocationInThumbView)
                        {
                            Window1.MainWindow.Dispatcher.BeginInvoke(new VoidDelegate(() =>
                            {
                                Window1.MainWindow.CollectionViews.ForEach(o => o.ClearSelected());
                                Window1.MainWindow.CollectionViews.ForEach(o => o.ToggleSelection(_vmFull, true));
                            }), DispatcherPriority.Send);
                        }

                        _window.FileImageViewModel = vm;
                    }
                }
            }
        }

        public bool IsShowing
        {
            get { return _window != null; }
        }

        public void OnWantNextImage()
        {
            if (_window != null)
            {
                _window.OnWantNextImage();
            }
        }

        public void OnWantPreviousImage()
        {
            if (_window != null)
            {
                _window.OnWantNextImage();
            }
        }

        public void DeleteImage()
        {
            var oldImage = _window.FileImageViewModel;
            var cvm = FindFileImageCollection(_window.FileImageViewModel.FileName);
            var image = cvm.GetNext(_window.FileImageViewModel.FileName, true);

            if (image != null)
            {
                OpenWindow(image);
            }
            else
            {
                cvm = FindFileImageCollection(_window.FileImageViewModel.FileName);
                image = cvm.GetPrevious(_window.FileImageViewModel.FileName, true);

                if (image != null)
                {
                    OpenWindow(image);
                }
            }

            Window1 window = _parentWindow as Window1;
            if (window._AllFileImageCollectionViewModels != null)
            {
                window._AllFileImageCollectionViewModels.ForEach(o => o.Delete(oldImage));
            }
            Debug.WriteLine("Deleted " + oldImage.FileName);
        }

        private void _newWindow_Closed(object sender, EventArgs e)
        {
            FileImageCollectionViewModel cvm = null;
            if (_window.FileImageViewModel != null)
            {
                cvm = FindFileImageCollection(_window.FileImageViewModel.FileName);
            }
            _windowClosed = true;
            _window.WantNextImage -= newWindow_WantNextImage;
            _window.WantPreviousImage -= newWindow_WantPreviousImage;
            _window.Closed -= _newWindow_Closed;
            _window.RequestDelete -= viewer_RequestDelete;
            _window.Closing -= viewer_Closing;
            Closed.RaiseEvent(this);
            _window.FileImageViewModel = null;
            _window.fullView.ClearAll();
            _window = null;
            if (cvm != null)
            {
                cvm._currentIndex = -1;
            }
        }

        private void newWindow_WantPreviousImage(object sender, EventArgs e)
        {
            var cvm = FindFileImageCollection(_window.FileImageViewModel.FileName);
            var image = cvm.GetPrevious(_window.FileImageViewModel.FileName, true);

            if (image != null)
                OpenWindow(image);
        }

        private void newWindow_WantNextImage(object sender, EventArgs e)
        {
            var cvm = FindFileImageCollection(_window.FileImageViewModel.FileName);
            var image = cvm.GetNext(_window.FileImageViewModel.FileName, true);

            if (image != null)
                OpenWindow(image);
        }

        public void ViewFullImage()
        {
            var cvm = FindCollectionView(_window.FileImageViewModel.FileName);
            var images = cvm.GetSelectedImages();

            if (images.Count == 0)
                return;

            OpenWindow(images[0]);
        }


    }
}
